﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////

#pragma once

// std headers
#include <string>

// qt headers
#include <QNetworkReply>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonValue>
#include <QJsonArray>
#include <QJsonParseError>

// custom headers
#include "IGcsLogger.h"


namespace gmepgcs
{
    template<typename TResult>
    class IResponseHandler
    {
    public:
        explicit IResponseHandler();
        virtual ~IResponseHandler();

    public:
        virtual TResult Handle(QNetworkReply *pReply, std::wstring & errorMessage);

    protected:
        virtual void HandleBody(const QJsonObject &body) = 0;

    private:
        void PrivateHandle(QNetworkReply * pReply);

    protected:
        TResult m_result;
        std::wstring m_errorMessage;
    };


    template<typename TResult>
    inline IResponseHandler<TResult>::IResponseHandler() :
        m_result(),
        m_errorMessage()
    {
    }

    template<typename TResult>
    inline IResponseHandler<TResult>::~IResponseHandler()
    {
    }

    template<typename TResult>
    inline TResult IResponseHandler<TResult>::Handle(QNetworkReply * pReply, std::wstring & errorMessage)
    {
        m_result = TResult();
        m_errorMessage = std::wstring();

        PrivateHandle(pReply);

        errorMessage = m_errorMessage;
        return m_result;
    }

    template<typename TResult>
    inline void IResponseHandler<TResult>::PrivateHandle(QNetworkReply * pReply)
    {
        if (pReply == nullptr)
        {
            m_errorMessage = L"Reply is null!";
            return;
        }

        if (pReply->error() != QNetworkReply::NoError)
        {
            int32_t statusCode = pReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
            auto errorStr = pReply->errorString();
            QString qErrorMessage = QString("request error:http code - %1, message - %2").arg(statusCode).arg(errorStr);
            IGcsLogger::Get()->Error(QString("fail to get response from %1.").arg(pReply->url().toString()) + qErrorMessage);

            m_errorMessage = qErrorMessage.toStdWString();
            return;
        }

        QByteArray jsonResponseBodyBytes = pReply->readAll();
        IGcsLogger::Get()->Info(QString("succeed to get response from %1. response body:").arg(pReply->url().toString()) + QString::fromUtf8(jsonResponseBodyBytes));

        QJsonParseError parseError;
        QJsonDocument jsonResponseBodyDoc = QJsonDocument::fromJson(jsonResponseBodyBytes, &parseError);
        if (parseError.error != QJsonParseError::ParseError::NoError)
        {
            QString qErrorMessage = QString("fail to parse response body:error type - %1").arg((int32_t)parseError.error);
            IGcsLogger::Get()->Error(qErrorMessage);

            m_errorMessage = qErrorMessage.toStdWString();
            return;
        }

        QJsonObject jsonResponseBody = jsonResponseBodyDoc.object();
        HandleBody(jsonResponseBody);
    }
}